package com.xt.base.dao.hibernate.code;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.hibernate.FlushMode;
import org.hibernate.Session;

import com.xt.base.dao.hibernate.HiberSessionHolder;

public class CodeGenerator {

	private Map<String, Long> codes = null;

	private Map<String, String> classes = null;

	private String serverCode;

	private final String module = "0000000000";

	private static CodeGenerator instance = null;

	private CodeGenerator() {
		this.codes = new HashMap<String, Long>();
		this.classes = new HashMap<String, String>();
		this.serverCode = AffairParameter.getInstance().getServercode();
	}

	synchronized private static CodeGenerator instance() {
		if (instance == null)
			instance = new CodeGenerator();
		return instance;
	}

	@SuppressWarnings("unchecked")
	synchronized private String getCode(Class clazz,Session session) throws CodeCreateException {
		String name = clazz.getName();
		if (!classes.containsKey(name))
			classes.put(name, getClassName(clazz));
		name = classes.get(name);
		long code = 0;
		if (!codes.containsKey(name)) {
			try {
				//Session session = HiberSessionHolder.getReadOnlySession();
				if(session==null) session = HiberSessionHolder.getReadOnlySession();
				session.setFlushMode(FlushMode.COMMIT);
				String queryStr = "select max(code) from " + name
						+ " where length(code)=15 and code like '" + serverCode
						+ "%'";
				List<String> codeList = (List<String>) session.createQuery(
						queryStr).list();
				if (codeList != null && codeList.size() > 0) {
					for (String codeStr : codeList) {
						long v = StringUtils.isEmpty(codeStr) ? 0 : new Long(
								codeStr.split(serverCode)[1]).longValue();
						if (v > code)
							code = v;
					}
				}
			} catch (ArrayIndexOutOfBoundsException e) {
				throw new CodeCreateException("www");
			} catch (Exception e) {
				e.printStackTrace();
				throw new CodeCreateException(e);
			}/*finally{
				HiberSessionHolder.closeSession();
			}*/
		} else
			code = codes.get(name).longValue();
		codes.put(name, ++code);
		String temp = String.valueOf(code);
		return serverCode + module.substring(0, 10 - temp.length()) + temp;
	}

	public static void setCode(IAutoCreateCode arg,Session session) {
		try {
			arg.setCode(instance().getCode(arg.getClass(),session));
			arg.afterSetCode();
		} catch (CodeCreateException e) {
			throw new RuntimeException(e);
		}
	}

	public static void setCodes(IAutoCreateCode arg,Session session) {
		for (IAutoCreateCode iac : arg.getTargets())
			setCode(iac,session);
	}

	private String getClassName(Class<?> clazz) {
		Class<?> returnClass = clazz;
		while (true) {
			Class<?> sClass = returnClass.getSuperclass();
			if (!IAutoCreateCode.class.isAssignableFrom(sClass))
				break;
			else
				returnClass = sClass;
		}
		return returnClass.getName();
	}
}
